package timbap.visualizer.api.model;

/**
 * The <code>AbstractTimeCode</code> class provides a common base
 * implementation of the <code>TimeCode</code> interface
 * that should be used by all specific implementations.
 *
 * @author  Andreas Pabst
 * @see     timbap.visualizer.api.model.TimeCode
 */
public abstract class AbstractTimeCode implements TimeCode {

    public static final float ABSOLUTE_POSITION_ERROR_VALUE = -1;
    public static final float NORMALIZED_ABSOLUTE_POSITION_DELTA_JUMP_DETECTION_THRESHOLD = 0.01f;

    private float absolutePosition = -1;
    private float velocity = 0;
    private float signalPower = 0;
    private float absolutePositionDelta = 0;
    private float fractionPlayed = 0;
    private boolean onFlipSide = false;

    public abstract float getMaximumAbsolutePosition();

    public boolean hasJumped() {
    	return (Math.abs(getNormalizedAbsolutePositionDelta())
    			 > NORMALIZED_ABSOLUTE_POSITION_DELTA_JUMP_DETECTION_THRESHOLD);
    }

    public boolean isReverse() {
        if (isAbsolutePositionValid()) {
            return (absolutePositionDelta < 0);
        } else {
            return (velocity < 0);
        }
    }
    public boolean isAbsolutePositionValid() {
        return (absolutePosition != ABSOLUTE_POSITION_ERROR_VALUE
            && Math.signum(absolutePositionDelta) == Math.signum(velocity));
    }

    public float getAbsolutePosition() {
        return absolutePosition;
    }
    public float getNormalizedAbsolutePosition() {
        return (absolutePosition / getMaximumAbsolutePosition()) % getMaximumAbsolutePosition();
    }
    public void setAbsolutePosition(float pAbsolutePosition) {
    	float tAbsolutePositionDelta = pAbsolutePosition - absolutePosition;
    	if (tAbsolutePositionDelta != 0.0f) {
    		this.absolutePosition = pAbsolutePosition;
    		this.absolutePositionDelta = tAbsolutePositionDelta;
    	}
        onFlipSide = absolutePosition > getMaximumAbsolutePosition();
    }
    public float getAbsolutePositionDelta() {
        return absolutePositionDelta;
    }
    public float getNormalizedAbsolutePositionDelta() {
        return absolutePositionDelta / getMaximumAbsolutePosition();
    }
    public float getVelocity() {
        return velocity;
    }
    public void setVelocity(float pVelocity) {
        this.velocity = pVelocity;
    }
    public float getSignalPower() {
        return signalPower;
    }
    public void setSignalPower(float pSignalPower) {
        this.signalPower = pSignalPower;
    }
    public float getFractionPlayed() {
        return fractionPlayed;
    }
    public void setFractionPlayed(float pFractionPlayed) {
        this.fractionPlayed = pFractionPlayed;
    }

    public boolean isOnFlipSide() {
        return onFlipSide;
    }

    public void setOnFlipSide(final boolean pOnFlipSide) {
        onFlipSide = pOnFlipSide;
    }

    public String toString() {
        return "signalPower: " + signalPower + ", "
             + "velocity: " + velocity + ", "
             + "absolutePosition: " + absolutePosition + ", "
             + "fractionPlayed: " + fractionPlayed;
    }



}